﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

namespace UPNP.IO
{
    internal abstract class TcpIncomingBase
    {
        protected static readonly CultureInfo TcpCulture = CultureInfo.CreateSpecificCulture("en-US");

        public EndPoint Sender
        {
            get;
            private set;
        }

        public WebHeaderCollection Headers
        {
            get;
            private set;
        }

        public string StatusHeader
        {
            get; 
            private set;
        }

        public string Body
        {
            get;
            private set;
        }

        private void ParseReponse(string res)
        {
            Contract.Requires(string.IsNullOrEmpty(res));

            // split response lines
            var resLines = res.Split(
                new[] { '\n' }    // be tollerant here. accept even mac line break
                ).Select(o => o.Trim()).ToArray();      // clear lines

            if (resLines.Length < 1)
            {
                throw new SsdpInvalidResponseException("Response from " + this.Sender + " does not contain at least a single line of text");
            }

            // the first line should contain an sttaus
            this.StatusHeader = resLines[0];

            // parse the other lines which must contain
            // the "KEY: VALUE" format
            var r = new WebHeaderCollection();

            for (var i = 1; i < resLines.Length; i++)
            {
                var line = resLines[i];

                // an empty line marks the end
                // of the HTTP header
                if (string.IsNullOrEmpty(line))
                {
                    // handle body
                    this.Body = string.Join(
                        string.Empty, 
                        resLines, 
                        i, 
                        resLines.Length - i
                        ).Trim();

                    break;
                }

                var sepPos = line.IndexOf(':');

                // skip malformatted lines
                if (sepPos < 0)
                    continue;

                // add line
                r.Add(
                    line.Substring(0, sepPos).Trim(),
                    line.Substring(sepPos + 1).Trim()
                    );
            }

            // done
            this.Headers = r;
        }

        public TcpIncomingBase(EndPoint sender, byte[] response)
            : this(sender, Encoding.ASCII.GetString(response))
        {
            Contract.Requires(sender != null);
            Contract.Requires(response != null);
        }

        public TcpIncomingBase(EndPoint sender, string response)
        {
            Contract.Requires(sender != null);
            Contract.Requires(!string.IsNullOrEmpty(response));

            this.Sender = sender;

            ParseReponse(response);
        }
    }
}
